package com.cl.unipay4j.wx.transfer;

import com.alibaba.fastjson.JSON;
import com.cl.unipay4j.core.IPayConfig;
import com.cl.unipay4j.core.Result;
import com.cl.unipay4j.core.UnipayConst;
import com.cl.unipay4j.core.transfer.ITransfer;
import com.cl.unipay4j.core.transfer.TransferResponse;
import com.cl.unipay4j.core.transfer.TransferToAccountModel;
import com.cl.unipay4j.core.transfer.TransferToBankModel;
import com.cl.unipay4j.core.util.EnumUtil;
import com.cl.unipay4j.core.util.MoneyUtil;
import com.cl.unipay4j.core.util.StrUtil;
import com.cl.unipay4j.wx.AbstractWxPay;
import com.cl.unipay4j.wx.sdk.WXPayConstants;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName WxPayTrabsfer
 * @Description
 * @Author Small
 * @Date 2020/7/31 14:12
 * @Version 1.0
 **/
@Slf4j
public class WxPayTransfer extends AbstractWxPay implements ITransfer {


    public WxPayTransfer() {
    }

    public WxPayTransfer(IPayConfig payConfig) {
        super(payConfig);
    }

    /**
     * 单笔转账到账户余额
     *
     * @param model
     * @return
     */
    @Override
    public Result<TransferResponse> execTransferToAccount(TransferToAccountModel model) {
        log.info("WxTransfer::=>订单{} 转账请求到达", model.getOutTradeNo());
        try {
            Map<String, String> r = initWxPay().transfer(wrapParam2Account(model));
            log.info("返回报文：" + JSON.toJSONString(r));
            String returnCode = r.get(WXPayConstants.RETURN_CODE);
            if (UnipayConst.SUCCESS.equals(returnCode)) {
                String resultCode = r.get(WXPayConstants.RESULT_CODE);
                if (UnipayConst.SUCCESS.equals(resultCode)) {
                    return Result.tradeSuccess(wrapperResponse(r));
                } else {
                    String errCode = r.get(WXPayConstants.ERR_CODE);
                    String errCodeDes = r.get(WXPayConstants.ERR_CODE_DES);
                    log.info("WxTransfer::=>订单{} 转账失败,错误代码{},错误原因{}", model.getOutTradeNo(), errCode, errCodeDes);
                    return Result.tradeFail(resultCode,errCode, errCodeDes);
                }
            } else {
                String returnMsg = r.get(WXPayConstants.RETURN_MSG);
                log.info("WxTransfer::=>订单{} 转账失败,错误代码{},错误原因{}", model.getOutTradeNo(), returnCode, returnMsg);
                return Result.returnFail(returnCode, returnMsg);
            }

        } catch (Exception e) {
            log.warn("WxTransfer=>订单{} 转账发生异常", model.getOutTradeNo(), e);
        }
        return Result.exception();
    }

    /**
     * 单笔转账到银行卡
     * @param model
     * @return
     */
    @Override
    public Result<TransferResponse> execTransferToBank(TransferToBankModel model) {
        log.info("WxTransfer::=>订单{} 转账请求到达", model.getOutTradeNo());
        try {
            Map<String, String> r = initWxPay().transfeToBank(wrapParam2Bank(model));
            String returnCode = r.get(WXPayConstants.RETURN_CODE);
            if (UnipayConst.SUCCESS.equals(returnCode)) {
                if (UnipayConst.SUCCESS.equals(r.get(WXPayConstants.RESULT_CODE))) {
                    return Result.tradeSuccess(wrapperResponse(r));
                } else {
                    String errCode = r.get(WXPayConstants.ERR_CODE);
                    String errCodeDes = r.get(WXPayConstants.ERR_CODE_DES);
                    log.info("WxTransfer::=>订单{} 转账失败,错误代码{},错误原因{}", model.getOutTradeNo(), errCode, errCodeDes);
                    return Result.returnFail(errCode, errCodeDes);
                }
            } else {
                String returnMsg = r.get(WXPayConstants.RETURN_MSG);
                log.info("WxTransfer::=>订单{} 转账失败,错误代码{},错误原因{}", model.getOutTradeNo(), returnCode, returnMsg);
                return Result.returnFail(returnCode, returnMsg);
            }

        } catch (Exception e) {
            log.warn("WxTransfer=>订单{} 转账发生异常", model.getOutTradeNo(), e);
        }
        return Result.exception();
    }

    private Map<String, String> wrapParam2Account(TransferToAccountModel model) {
        Map<String, String> map = new HashMap<>();
        map.put("partner_trade_no", model.getOutTradeNo());
        map.put("openid", model.getIdentity());
        map.put("check_name", model.isCheckName() ? WxTransferCheckNameEnum.FORCE_CHECK.getValue() : WxTransferCheckNameEnum.NO_CHECK.getValue());
        if (model.isCheckName()) {
            // 如果check_name设置为FORCE_CHECK，则必填用户真实姓名
            map.put("re_user_name", model.getReUserName());
            map.put("check_name", WxTransferCheckNameEnum.FORCE_CHECK.getValue());
        } else {
            map.put("check_name", WxTransferCheckNameEnum.NO_CHECK.getValue());
        }
        map.put("amount", String.valueOf(MoneyUtil.yuan2Cent(model.getAmount())));
        map.put("desc", model.getRemark());
        log.info("转账报文:" + JSON.toJSONString(map));
        return map;
    }

    private Map<String, String> wrapParam2Bank(TransferToBankModel model) {
        Map<String, String> map = new HashMap<>();
        map.put("partner_trade_no", model.getOutTradeNo());
        map.put("enc_bank_no", model.getBankNo());
        map.put("enc_true_name", model.getAccountName());
        map.put("bank_code", model.getBankCode());
        map.put("amount", String.valueOf(MoneyUtil.yuan2Cent(model.getAmount())));
        map.put("desc", model.getRemark());
        return map;
    }

    /**
     * 转账成功时返回的参数
     * @param r
     * @return
     */
    private TransferResponse wrapperResponse(Map<String, String> r) {
        TransferResponse response = new TransferResponse();
        response.setTransferState(WxTransferState.SUCCESS.getTransferState());
        // 商户订单号
        response.setOutTradeNo(r.get("partner_trade_no"));
        // 微信付款单号
        response.setTradeNo(r.get("payment_no"));
        String paymentAmount = r.get("payment_amount");
        response.setTotalAmount(StrUtil.isNotEmpty(paymentAmount) ? MoneyUtil.cent2Yuan(Integer.parseInt(paymentAmount)) : BigDecimal.ZERO);
        response.setBody(JSON.toJSONString(r));
        return response;
    }
}
